#include "List.h"

// Конструктор по умолчанию
template<typename T>
List<T>::List() {
	head = NULL;
}

// Деструктор, освобождающий всю выделенную память
template<typename T>
List<T>::~List() {
	// обход всего списка с удалением очередного элемента 
	for (element * i = head; i != NULL;) {
		// запоминаем указатель на текущий элемент 
		element * e = i;
		
		// сдвигаемся на следующий
		i = i->next;
		
		// удаляем элемент, на который указывает указатель e
		delete e;			
	}
}

// Операция вставки элемента в начала списка
template<typename T>
void List<T>::push_front(const T& value) {
	// создаем новый элемент для сохранения значения value
	element * e = new element;
	
	// сохраняем значение value в поле data 
	e->data = value;
	
	// устанавливаем указатель next на начало списка
	e->next = head;
	
	// устанавливаем начало списка на новосозданный элемент
	head = e;
}

// Операция удаления первого элемента списка
template<typename T>
void List<T>::pop_front() {
	// если список не пуст ( т.е. есть ли что удалять... )
	if (!empty()) {
		// запоминаем указатель на начало списка
		element * e = head;
		
		// сдвигаем указатель начала списка на следующий элемент списка
		head = head->next;
		
		// удаляем элемент, на который указывает указатель e
		delete e;
	}
}

// Операция вставки элемента в конец списка
template<typename T>
void List<T>::push_back(const T& value) {
	// создаем новый элемент для сохранения значения value
	element * e = new element;
	
	// сохраняем значение value в поле data 
	e->data = value;
	
	// этот элемент будет последним в списке
	e->next = NULL;
	
	if (empty()) {
		head = e;
	}
	else {
		// цикл для прохода по всему списку 
		// чтобы прийти в последний элемент, 
		// после которого будем добавлять новый элемент
		element * i = head;
		while (i->next != NULL) { 
			i = i->next;
		}
		
		// добавляем новый элемент в конец списка
		i->next = e;
	}
}
	
// Операция удаления последнего элемента списка
template<typename T>
void List<T>::pop_back() {	
	// если список не пуст ( т.е. есть ли что удалять... )
	if (!empty()) {
		// создаем два указателя. 
		// curr_element указывает на "текуший" элемент
		element * curr_element = head;
		// prev_element указывает на предыдущий элемент по отношению к curr_element
		element * prev_element = NULL;
		
		// пока не дойдем до последнего элемента списка
		while (curr_element->next != NULL) {
			// передвигаем указатели
			curr_element = curr_element->next;
			prev_element = prev_element == NULL ? head : prev_element->next;
		}

		// после выхода из цикла curr_element указывает на последний элемент списка
		// удаляем его
		delete curr_element;
		
		// если после выхода из цикла prev_element == NULL 
		// то это означает что в списке был всего один элемент
		if (prev_element == NULL) {
			// Устанавливаем указатель на начала списка в NULL 
			// в знак того, что список теперь пуст
			head = NULL;
		}
		else { // в списке было больше одного элемента
			// нужно "закончить" список
			prev_element->next = NULL;
		}
	}
}

// Распечатывает список
template<typename T>
void List<T>::print()
{
	std::cout << std::endl << "Using iterator..." << std::endl; 
	
	for (List<int>::Iterator i = this->begin(); i != this->end(); i++) {
		std::cout << *i << " ";
	}
	
	std::cout << std::endl;
}

// Метод проверяющий пуст ли список. Возвращает true если список пуст и false иначе
template<typename T>
bool List<T>::empty() const {
	return head == NULL;
}
